/**
 ** 普通运算指令保留站
**/
module AluSaveStation(
    input wire clk,
    input wire save_en_1,                  //保存到保留站的使能信号
    input wire save_en_2,
    input wire [11:0] pc_1, pc_2,
    input wire [2:0] work_mode_1,           //运算模式--普通整数运算 or 整数乘除法 or 浮点
    input wire [2:0] work_mode_2,
    input wire [3:0] alu_ctrl_1,           //运算器的控制信号
    input wire [3:0] alu_ctrl_2,
    input wire [31:0] imm_1, imm_2,        //立即数的输入  
    input wire rs_1_ready,                 //寄存器是否准备就绪的标记
    input wire rt_1_ready,             
    input wire rs_2_ready,             
    input wire rt_2_ready,             
    input wire [4:0] rs_1_relation,    //和rs寄存器关联的ROB号
    input wire [4:0] rt_1_relation,    //和rt寄存器关联的ROB号
    input wire [4:0] rd_1_relation,    //和rd寄存器关联的ROB号
    input wire [4:0] rs_2_relation,    //和rs寄存器关联的ROB号
    input wire [4:0] rt_2_relation,    //和rt寄存器关联的ROB号
    input wire [4:0] rd_2_relation,    //和rd寄存器关联的ROB号
    input wire rd_1_flag, rd_2_flag,
    input wire [31:0] rs_1_value,      //寄存器的值
    input wire [31:0] rt_1_value,      
    input wire [31:0] rs_2_value,      //寄存器的值
    input wire [31:0] rt_2_value,
    input wire alu_commit_en_1, alu_commit_en_2, mul_commit_en_1, mul_commit_en_2,
    input wire [31:0] alu_commit_value_1, alu_commit_value_2, mul_commit_value_1, mul_commit_value_2,
    input wire [4:0] alu_commit_save_no_1, alu_commit_save_no_2, mul_commit_save_no_1, mul_commit_save_no_2, 
    input wire [4:0] alu_commit_rob_no_1, alu_commit_rob_no_2, mul_commit_rob_no_1, mul_commit_rob_no_2, 
    output reg [31:0] alu_x_1, alu_y_1, alu_x_2, alu_y_2,
    output reg [3:0] cAlu_ctrl_1, cAlu_ctrl_2,
    output reg alu_ready_en_1, alu_ready_en_2,
    output reg [4:0] alu_save_no_1, alu_save_no_2, alu_rob_no_1, alu_rob_no_2
);

    //保留站的一些数组，用来存储在此地等待的指令的信息
    reg [31:0] rs_ok, rt_ok, item_ok;                          //寄存器是否准备好的标记位
    reg [31:0] rs_value[0:15], rt_value[0:15], imm[0:15];      //寄存器对应的值
    reg [4:0] rs_relation[0:15], rt_relation[0:15], rd_relation[0:15];  
    reg [31:0] rd_flag;
    reg [11:0] pc[0:15];
    reg [3:0] alu_ctrl[0:15];                                  //运算器的控制信号
    reg [2:0] work_mode[0:15];                                 //运算模式，用来选择运算器 

    //定义空闲队列，方便查找到空闲可用的保留站条目
    reg [4:0] freeQueue[0:15];
    reg [4:0] free_tail;
    reg [4:0] free_head;
    reg [4:0] free_temp_index;
    //保留站号
    reg [4:0] compare_save_no [0:31];

    //遍历需要的指针
    integer i, j;
    

    initial begin
        free_temp_index <= 0;
        //初始化空闲队列指针
        free_head <= 0;
        free_tail <= 31;  //初始情况下，所有的保留站条目都是可用的，即队列是满的
        //初始化保留站和队列
        for (i=0; i<16; i=i+1) begin
            rs_ok[i] <= 0; 
            rt_ok[i] <= 0;
            item_ok[i] <= 0;
            freeQueue[i] <= i;
            compare_save_no[i] <= i;
        end
    end

    //第一阶段分配的保留站的条目块号
    reg [4:0] save_no_1_stage1, save_no_2_stage1;
    reg save_en_1_stage1, save_en_2_stage1;
    //第一阶段需要向后传递的信号
    reg [11:0] pc_1_stage1, pc_2_stage1;
    reg [2:0] work_mode_1_stage1, work_mode_2_stage1;
    reg [31:0] imm_1_stage1, imm_2_stage1;
    reg [3:0] alu_ctrl_1_stage1, alu_ctrl_2_stage1;
    reg rs_1_ready_stage1, rt_1_ready_stage1;
    reg rs_2_ready_stage1, rt_2_ready_stage1;
    reg [4:0] rs_1_relation_stage1, rt_1_relation_stage1, rd_1_relation_stage1; 
    reg [4:0] rs_2_relation_stage1, rt_2_relation_stage1, rd_2_relation_stage1;
    reg [31:0] rs_1_value_stage1, rt_1_value_stage1, rs_2_value_stage1, rt_2_value_stage1;
    
    always @(posedge clk) begin
        //分配空闲保留站块
        if (save_en_1==1 && save_en_2==1 && work_mode_1==3'b000 && work_mode_2==3'b000) begin
            save_no_1_stage1 <= freeQueue[free_head];
            save_no_2_stage1 <= freeQueue[(free_head+1)%16];
            //指针后移
            free_head <= (free_head+2)%16;
            save_en_1_stage1 <= 1;
            save_en_2_stage1 <= 1;
        end
        else if (save_en_1==1 && work_mode_1==3'b000) begin
            save_no_1_stage1 <= freeQueue[free_head];
            //指针后移
            free_head <= (free_head+1)%16;
            save_en_1_stage1 <= 1;
            save_en_2_stage1 <= 0;
        end
        else if (save_en_2==1 && work_mode_2==3'b000) begin
            save_no_2_stage1 <= freeQueue[free_head];
            //指针后移
            free_head <= (free_head+1)%16;
            save_en_1_stage1 <= 0;
            save_en_2_stage1 <= 1;
        end
        else begin
            save_en_1_stage1 <= 0;
            save_en_2_stage1 <= 0;
        end

        //将现在没用到的信号传递到下一级
        pc_1_stage1 <= pc_1;
        pc_2_stage1 <= pc_2;
        work_mode_1_stage1 <= work_mode_1;
        work_mode_2_stage1 <= work_mode_2;
        imm_1_stage1 <= imm_1;
        imm_2_stage1 <= imm_2;
        alu_ctrl_1_stage1 <= alu_ctrl_1; 
        alu_ctrl_2_stage1 <= alu_ctrl_2; 
        rs_1_ready_stage1 <= rs_1_ready;
        rt_1_ready_stage1 <= rt_1_ready;     
        rs_2_ready_stage1 <= rs_2_ready;     
        rt_2_ready_stage1 <= rt_2_ready;     
        rs_1_relation_stage1 <= rs_1_relation; 
        rt_1_relation_stage1 <= rt_1_relation; 
        rd_1_relation_stage1 <= rd_1_relation; 
        rs_2_relation_stage1 <= rs_2_relation;
        rt_2_relation_stage1 <= rt_2_relation;
        rd_2_relation_stage1 <= rd_2_relation;
        rs_1_value_stage1 <= rs_1_value;
        rt_1_value_stage1 <= rt_1_value;      
        rs_2_value_stage1 <= rs_2_value;
        rt_2_value_stage1 <= rt_2_value; 
    end

    //现在这里还是会出现同时更改就绪队列指针的情况，需要调整结构避免这种竞争状态的发生
    always @(posedge clk) begin
        if (save_en_1_stage1==1) begin
            //将数据写入到保留站备用
            rs_value[save_no_1_stage1] <= rs_1_value_stage1;
            rt_value[save_no_1_stage1] <= rt_1_value_stage1;
            rd_relation[save_no_1_stage1] <= rd_1_relation_stage1;
            rd_flag[save_no_1_stage1] <= rd_1_flag;
            work_mode[save_no_1_stage1] <= work_mode_1_stage1;
            pc[save_no_1_stage1] <= pc_1_stage1;
            imm[save_no_1_stage1] <= imm_1_stage1;
            alu_ctrl[save_no_1_stage1] <= alu_ctrl_1_stage1;
            //$display("ALU保留站号: ",save_no_1_stage1, " ROB号: ", rd_1_relation_stage1);
            if (rs_1_ready_stage1==1) begin 
                //操作数rs，已经准备好
                rs_ok[save_no_1_stage1] <= 1;
            end
            else begin
                rs_ok[save_no_1_stage1] <= 0;
                rs_relation[save_no_1_stage1] <= rs_1_relation_stage1;
            end

            if (rt_1_ready_stage1==1) begin
                //操作数rt，已经准备好
                rt_ok[save_no_1_stage1] <= 1;
            end
            else begin
                rt_ok[save_no_1_stage1] <= 0;
                rt_relation[save_no_1_stage1] <= rt_1_relation_stage1;
            end
            item_ok[save_no_1_stage1] <= rt_1_ready_stage1 && rs_1_ready_stage1;
        end

        if (save_en_2_stage1==1) begin
            //处理第二条指令
            //将数据写入到保留站备用
            rs_value[save_no_2_stage1] <= rs_2_value_stage1;
            rt_value[save_no_2_stage1] <= rt_2_value_stage1;
            rd_relation[save_no_2_stage1] <= rd_2_relation_stage1;
            rd_flag[save_no_2_stage1] <= rd_2_flag;
            work_mode[save_no_2_stage1] <= work_mode_2_stage1;
            pc[save_no_2_stage1] <= pc_2_stage1;
            imm[save_no_2_stage1] <= imm_2_stage1;
            alu_ctrl[save_no_2_stage1] <= alu_ctrl_2_stage1;
            //$display("ALU保留站号: ",save_no_2_stage1, " ROB号: ", rd_2_relation_stage1);

            if (rs_2_ready_stage1==1) begin
                rs_ok[save_no_2_stage1] <= 1;
            end
            else begin
                rs_ok[save_no_2_stage1] <= 0;
                rs_relation[save_no_2_stage1] <= rs_2_relation_stage1;
            end

            if (rt_2_ready_stage1==1) begin
                rt_ok[save_no_2_stage1] <= 1;
            end
            else begin
                rt_ok[save_no_2_stage1] <= 0;
                rt_relation[save_no_2_stage1] <= rt_2_relation_stage1;
            end
            item_ok[save_no_2_stage1] <= rs_2_ready_stage1 && rt_2_ready_stage1;
        end
    end

    //运算结果的写回逻辑 -- 目前的想法是，以前的那个逻辑在仿真能够通过，但是可能要占据较大的面积
    always @(posedge clk) begin
        for (i=0; i<16; i=i+1) begin
            //如果的保留站条目确实在等待这个结果的写回，更新之
            if (alu_commit_en_1) begin
                if (rs_relation[i]==alu_commit_rob_no_1) begin
                    rs_value[i] <= alu_commit_value_1;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==alu_commit_rob_no_1) begin
                    rt_value[i] <= alu_commit_value_1;
                    rt_ok[i] <= 1;
                end
            end

            if (alu_commit_en_2) begin
                if (rs_relation[i]==alu_commit_rob_no_2) begin
                    rs_value[i] <= alu_commit_value_2;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==alu_commit_rob_no_2) begin
                    rt_value[i] <= alu_commit_value_2;
                    rt_ok[i] <= 1;
                end
            end

            if (mul_commit_en_1) begin
                if (rs_relation[i]==mul_commit_rob_no_1) begin
                    rs_value[i] <= mul_commit_value_1;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==mul_commit_rob_no_1) begin
                    rt_value[i] <= mul_commit_value_1;
                    rt_ok[i] <= 1;
                end
            end

            if (mul_commit_en_2) begin
                if (rs_relation[i]==mul_commit_rob_no_2) begin
                    rs_value[i] <= mul_commit_value_2;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==mul_commit_rob_no_2) begin
                    rt_value[i] <= mul_commit_value_2;
                    rt_ok[i] <= 1;
                end
            end

            //如果寄存器都属于就绪状态，更新其整个条目的就绪状态
            if (rt_ok[i] && rs_ok[i]) begin
                item_ok[i] <= 1;
            end
            else begin
                item_ok[i] <= 0;
            end
        end
    end


    //设置比较电路，寻找最应该发射的条目
    //比较电路结构中会用到的一些信号
    wire [4:0] level1_rob_out [0:7];
    wire level1_rob_flag_out [0:7];
    wire [4:0] level1_save_no_out [0:7];
    wire level1_ready_out [0:7];
    wire [4:0] level2_rob_out [0:3];
    wire level2_rob_flag_out [0:3];
    wire [4:0] level2_save_no_out [0:3];
    wire level2_ready_out [0:3];
    wire [4:0] level3_rob_out [0:1];
    wire level3_rob_flag_out [0:1];
    wire [4:0] level3_save_no_out [0:1];
    wire level3_ready_out [0:1];
    wire [4:0] final_rob_no;
    wire final_rob_flag;
    wire [4:0] final_save_no;
    wire final_ready_out; 
    reg [4:0] select_save_no_tmep;
    reg select_ready_temp;

    //实例化第一层分治比较电路
    compareItem level1_1(.rob_1_in(rd_relation[0]), .rob_flag_1_in(rd_flag[0]), .save_no_1_in(compare_save_no[0]), .ready_1_in(item_ok[0]), .rob_2_in(rd_relation[1]), .rob_flag_2_in(rd_flag[1]), .save_no_2_in(compare_save_no[1]), .ready_2_in(item_ok[1]), .rob_out(level1_rob_out[0]), .rob_flag_out(level1_rob_flag_out[0]), .save_no_out(level1_save_no_out[0]), .ready_out(level1_ready_out[0]));
    compareItem level1_2(.rob_1_in(rd_relation[2]), .rob_flag_1_in(rd_flag[2]), .save_no_1_in(compare_save_no[2]), .ready_1_in(item_ok[2]), .rob_2_in(rd_relation[3]), .rob_flag_2_in(rd_flag[3]), .save_no_2_in(compare_save_no[3]), .ready_2_in(item_ok[3]), .rob_out(level1_rob_out[1]), .rob_flag_out(level1_rob_flag_out[1]), .save_no_out(level1_save_no_out[1]), .ready_out(level1_ready_out[1]));
    compareItem level1_3(.rob_1_in(rd_relation[4]), .rob_flag_1_in(rd_flag[4]), .save_no_1_in(compare_save_no[4]), .ready_1_in(item_ok[4]), .rob_2_in(rd_relation[5]), .rob_flag_2_in(rd_flag[5]), .save_no_2_in(compare_save_no[5]), .ready_2_in(item_ok[5]), .rob_out(level1_rob_out[2]), .rob_flag_out(level1_rob_flag_out[2]), .save_no_out(level1_save_no_out[2]), .ready_out(level1_ready_out[2]));
    compareItem level1_4(.rob_1_in(rd_relation[6]), .rob_flag_1_in(rd_flag[6]), .save_no_1_in(compare_save_no[6]), .ready_1_in(item_ok[6]), .rob_2_in(rd_relation[7]), .rob_flag_2_in(rd_flag[7]), .save_no_2_in(compare_save_no[7]), .ready_2_in(item_ok[7]), .rob_out(level1_rob_out[3]), .rob_flag_out(level1_rob_flag_out[3]), .save_no_out(level1_save_no_out[3]), .ready_out(level1_ready_out[3]));
    compareItem level1_5(.rob_1_in(rd_relation[8]), .rob_flag_1_in(rd_flag[8]), .save_no_1_in(compare_save_no[8]), .ready_1_in(item_ok[8]), .rob_2_in(rd_relation[9]), .rob_flag_2_in(rd_flag[9]), .save_no_2_in(compare_save_no[9]), .ready_2_in(item_ok[9]), .rob_out(level1_rob_out[4]), .rob_flag_out(level1_rob_flag_out[4]), .save_no_out(level1_save_no_out[4]), .ready_out(level1_ready_out[4]));
    compareItem level1_6(.rob_1_in(rd_relation[10]), .rob_flag_1_in(rd_flag[10]), .save_no_1_in(compare_save_no[10]), .ready_1_in(item_ok[10]), .rob_2_in(rd_relation[11]), .rob_flag_2_in(rd_flag[11]), .save_no_2_in(compare_save_no[11]), .ready_2_in(item_ok[11]), .rob_out(level1_rob_out[5]), .rob_flag_out(level1_rob_flag_out[5]), .save_no_out(level1_save_no_out[5]), .ready_out(level1_ready_out[5]));
    compareItem level1_7(.rob_1_in(rd_relation[12]), .rob_flag_1_in(rd_flag[12]), .save_no_1_in(compare_save_no[12]), .ready_1_in(item_ok[12]), .rob_2_in(rd_relation[13]), .rob_flag_2_in(rd_flag[13]), .save_no_2_in(compare_save_no[13]), .ready_2_in(item_ok[13]), .rob_out(level1_rob_out[6]), .rob_flag_out(level1_rob_flag_out[6]), .save_no_out(level1_save_no_out[6]), .ready_out(level1_ready_out[6]));
    compareItem level1_8(.rob_1_in(rd_relation[14]), .rob_flag_1_in(rd_flag[14]), .save_no_1_in(compare_save_no[14]), .ready_1_in(item_ok[14]), .rob_2_in(rd_relation[15]), .rob_flag_2_in(rd_flag[15]), .save_no_2_in(compare_save_no[15]), .ready_2_in(item_ok[15]), .rob_out(level1_rob_out[7]), .rob_flag_out(level1_rob_flag_out[7]), .save_no_out(level1_save_no_out[7]), .ready_out(level1_ready_out[7]));
    
    //实例化第二层分治比较电路
    compareItem level2_1(.rob_1_in(level1_rob_out[0]), .rob_flag_1_in(level1_rob_flag_out[0]), .save_no_1_in(level1_save_no_out[0]), .ready_1_in(level1_ready_out[0]), .rob_2_in(level1_save_no_out[1]), .rob_flag_2_in(level1_rob_flag_out[1]), .save_no_2_in(level1_save_no_out[1]), .ready_2_in(level1_ready_out[1]), .rob_out(level2_rob_out[0]), .rob_flag_out(level2_rob_flag_out[0]),  .save_no_out(level2_save_no_out[0]), .ready_out(level2_ready_out[0]));
    compareItem level2_2(.rob_1_in(level1_rob_out[2]), .rob_flag_1_in(level1_rob_flag_out[2]), .save_no_1_in(level1_save_no_out[2]), .ready_1_in(level1_ready_out[2]), .rob_2_in(level1_save_no_out[3]), .rob_flag_2_in(level1_rob_flag_out[3]), .save_no_2_in(level1_save_no_out[3]), .ready_2_in(level1_ready_out[3]), .rob_out(level2_rob_out[1]), .rob_flag_out(level2_rob_flag_out[1]),  .save_no_out(level2_save_no_out[1]), .ready_out(level2_ready_out[1]));
    compareItem level2_3(.rob_1_in(level1_rob_out[4]), .rob_flag_1_in(level1_rob_flag_out[4]), .save_no_1_in(level1_save_no_out[4]), .ready_1_in(level1_ready_out[4]), .rob_2_in(level1_save_no_out[5]), .rob_flag_2_in(level1_rob_flag_out[5]), .save_no_2_in(level1_save_no_out[5]), .ready_2_in(level1_ready_out[5]), .rob_out(level2_rob_out[2]), .rob_flag_out(level2_rob_flag_out[2]),  .save_no_out(level2_save_no_out[2]), .ready_out(level2_ready_out[2]));
    compareItem level2_4(.rob_1_in(level1_rob_out[6]), .rob_flag_1_in(level1_rob_flag_out[6]), .save_no_1_in(level1_save_no_out[6]), .ready_1_in(level1_ready_out[6]), .rob_2_in(level1_save_no_out[7]), .rob_flag_2_in(level1_rob_flag_out[7]), .save_no_2_in(level1_save_no_out[7]), .ready_2_in(level1_ready_out[7]), .rob_out(level2_rob_out[3]), .rob_flag_out(level2_rob_flag_out[3]),  .save_no_out(level2_save_no_out[3]), .ready_out(level2_ready_out[3]));

    //实例化第三层分治比较电路
    compareItem level3_1(.rob_1_in(level2_rob_out[0]), .rob_flag_1_in(level2_rob_flag_out[0]), .save_no_1_in(level2_save_no_out[0]), .ready_1_in(level2_ready_out[0]), .rob_2_in(level2_rob_out[1]), .rob_flag_2_in(level2_rob_flag_out[1]), .save_no_2_in(level2_save_no_out[1]), .ready_2_in(level2_ready_out[1]), .rob_out(level3_rob_out[0]), .rob_flag_out(level3_rob_flag_out[0]), .save_no_out(level3_save_no_out[0]), .ready_out(level3_ready_out[0]));
    compareItem level3_2(.rob_1_in(level2_rob_out[2]), .rob_flag_1_in(level2_rob_flag_out[2]), .save_no_1_in(level2_save_no_out[2]), .ready_1_in(level2_ready_out[2]), .rob_2_in(level2_rob_out[3]), .rob_flag_2_in(level2_rob_flag_out[3]), .save_no_2_in(level2_save_no_out[3]), .ready_2_in(level2_ready_out[3]), .rob_out(level3_rob_out[1]), .rob_flag_out(level3_rob_flag_out[1]), .save_no_out(level3_save_no_out[1]), .ready_out(level3_ready_out[1]));
 
    //实例化最终比较电路
    compareItem level4(.rob_1_in(level3_rob_out[0]), .rob_flag_1_in(level3_rob_flag_out[0]), .save_no_1_in(level3_save_no_out[0]), .ready_1_in(level3_ready_out[0]), .rob_2_in(level3_rob_out[1]), .rob_flag_2_in(level3_rob_flag_out[1]), .save_no_2_in(level3_save_no_out[1]), .ready_2_in(level3_ready_out[1]), .rob_out(final_rob_no), .rob_flag_out(final_rob_flag), .save_no_out(final_save_no), .ready_out(final_ready_out));
    
    always @(negedge clk) begin
        select_save_no_tmep <= final_save_no;
        select_ready_temp <= item_ok[final_save_no];
        //$display("就绪保留站号: ",final_save_no," 准备状态: ", rs_ok[final_save_no]&&rt_ok[final_save_no]);
        //将就绪标记位置0
        rs_ok[final_save_no] <= 0;
        rt_ok[final_save_no] <= 0;
        item_ok[final_save_no] <= 0;
    end


    always @(posedge clk) begin
        //第一个运算器的输入
        alu_save_no_1 <= select_save_no_tmep;
        alu_rob_no_1 <= rd_relation[select_save_no_tmep];
        alu_ready_en_1 <= select_ready_temp;
        alu_x_1 <= rs_value[select_save_no_tmep];
        alu_y_1 <= rt_value[select_save_no_tmep];
        cAlu_ctrl_1 <= alu_ctrl[select_save_no_tmep];
        //$display("运算控制信号: ", alu_ctrl[select_save_no_tmep]);
        //第二个运算器的输入
        alu_save_no_2 <= final_save_no;
        alu_rob_no_2 <= rd_relation[final_save_no];
        alu_ready_en_2 <= item_ok[final_save_no];
        alu_x_2 <= rs_value[final_save_no];
        alu_y_2 <= rt_value[final_save_no];
        cAlu_ctrl_2 <= alu_ctrl[final_save_no];
        //$display("就绪保留站号: ",final_save_no," 准备状态: ", rs_ok[final_save_no]&&rt_ok[final_save_no]);
        //将就绪标记位置0
        rs_ok[final_save_no] <= 0;
        rt_ok[final_save_no] <= 0;
        item_ok[final_save_no] <= 0;
    end
endmodule